
#include <BChangeEvent>
#include <BObject>
#include "member_BObject.h"
#include "member_BWidget.h"

using namespace BWE;

#define member					(*(member_BObject*)_ptr)
#define member_allocate()		_ptr = new member_BObject(this)
#define member_release()		delete (member_BObject*)_ptr

BObject::BObject()
{
	member_allocate();
}
BObject::BObject(const BString& name)
{
	member_allocate();
	setName(name);
}
BObject::~BObject()
{
	member_release();
}

void BObject::setName(const BString& name)
{
	if (member.name != name)
	{
		member.name = name;
	}
}
const BString& BObject::name() const
{
	return member.name;
}

void BObject::setAble(bool able)
{
	if (able)
		enable();
	else
		disable();
}
bool BObject::able() const
{
	return member.able;
}

void BObject::enable()
{
	if (!member.able)
	{
		member.able = true;
		emit(Signal_Enable);
		if (BWidget* widget = dynamic_cast<BWidget*>(this))
		{
			BChangeEvent changeEvent(Change_Able);
			changeEvent.setAble(true);
			widget_member(widget)->procEvent(changeEvent);
		}
	}
}
void BObject::disable()
{
	if (member.able)
	{
		emit(Signal_Disable);
		member.able = false;
		if (BWidget* widget = dynamic_cast<BWidget*>(this))
		{
			BChangeEvent changeEvent(Change_Able);
			changeEvent.setAble(false);
			widget_member(widget)->procEvent(changeEvent);
		}
	}
}

bool BObject::lock()
{
	if(member.initMutex())
	{
#ifdef _LINUX_
		int error = pthread_mutex_lock(&member.mutex);
		return error == 0;
#else
		EnterCriticalSection(&member.criticalSection);
		return true;
#endif
	}
	return false;
}
bool BObject::unlock()
{
	if(member.initMutex())
	{
#ifdef _LINUX_
		int error = pthread_mutex_unlock(&member.mutex);
		return error == 0;
#else
		LeaveCriticalSection(&member.criticalSection);
		return true;
#endif
	}
	return false;
}
bool BObject::trylock()
{
	if(member.initMutex())
	{
#ifdef _LINUX_
		int error = pthread_mutex_trylock(&member.mutex);
		return error == 0;
#else
		BOOL ret = TryEnterCriticalSection(&member.criticalSection);
		return ret;
#endif
	}
	return false;
}

bool BObject::disconnect(int signal)
{
	SigProcMap& globalSigProcMap = member.globalSigProcMap();
	if(signal == 0)
	{
		for (SigProcArray& objects : globalSigProcMap)
			objects.remove(this);
	}
	else
	{
		SigProcArray& procs = globalSigProcMap[signal];
		procs.remove(this);
	}
	return true;
}
bool BObject::disconnect(const BString& signal)
{
	StrSigProcMap& globalStrSigProcMap = member.globalStrSigProcMap();
	if (signal.empty())
	{
		for (SigProcArray& procs : globalStrSigProcMap)
			procs.remove(this);
	}
	else
	{
		SigProcArray& procs = globalStrSigProcMap[signal];
		procs.remove(this);
	}
	return true;
}
bool BObject::disconnect(BObject* object, int signal)
{
	if (!object)
		return false;
	SigProcMap& sigProcMap = object_member(object)->sigProcMap;
	if (signal)
	{
		SigProcArray& procs = sigProcMap[signal];
		procs.remove(this);
	}
	else
	{
		for (SigProcArray& procs : sigProcMap)
			procs.remove(this);
	}
	return true;
}
bool BObject::disconnect(BObject* object, const BString& signal)
{
	if (!object)
		return false;
	StrSigProcMap& strSigProcMap = object_member(object)->strSigProcMap;
	if (signal.empty())
	{
		for (SigProcArray& procs : strSigProcMap)
			procs.remove(this);
	}
	else
	{
		SigProcArray& procs = strSigProcMap[signal];
		procs.remove(this);
	}
	return true;
}

bool BObject::emit(int signal, const BValue& value)
{
	if (!member.able || !signal)
		return false;
	SigProcArray& procs = member.sigProcMap(signal);
	for (int i = 0; i < procs.size(); i++)
	{
		SigProc& proc = procs[i];
		proc(this, value);
	}
	SigProcMap& globalSigProcMap = member.globalSigProcMap();
	SigProcArray& globalProcs = globalSigProcMap(signal);
	for (int i = 0; i < globalProcs.size(); i++)
	{
		SigProc& proc = globalProcs[i];
		proc(this, value);
	}
	return true;
}
bool BObject::emit(const BString& signal, const BValue& value)
{
	if (signal.empty())
		return false;
	SigProcArray& procs = member.strSigProcMap(signal);
	for (int i = 0; i < procs.size(); i++)
	{
		SigProc& proc = procs[i];
		proc(this, value);
	}
	StrSigProcMap& globalStrSigProcMap = member.globalStrSigProcMap();
	SigProcArray& globalProcs = globalStrSigProcMap(signal);
	for (int i = 0; i < globalProcs.size(); i++)
	{
		SigProc& proc = globalProcs[i];
		proc(this, value);
	}
	return true;
}
bool BObject::post(BObject* object, int signal, const BValue& value)
{
	if (!object)
		return false;
	if (!signal)
		return false;
	SigProcArray& procs = member.sigProcMap[signal];
	for (int i = 0; i < procs.size(); i++)
	{
		SigProc& proc = procs[i];
		if (proc == object)
		{
			proc(this, value);
		}
	}
	SigProcMap& globalSigProcMap = member.globalSigProcMap();
	SigProcArray& globalProcs = globalSigProcMap[signal];
	for (int i = 0; i < globalProcs.size(); i++)
	{
		SigProc& proc = globalProcs[i];
		if (proc == object)
		{
			proc(this, value);
		}
	}
	return true;
}
bool BObject::post(BObject* object, const BString& signal, const BValue& value)
{
	if (!object)
		return false;
	if (signal.empty())
		return false;
	SigProcArray& procs = member.strSigProcMap[signal];
	for (int i = 0; i < procs.size(); i++)
	{
		SigProc& proc = procs[i];
		if (proc == object)
		{
			proc(this, value);
		}
	}
	StrSigProcMap& globalSigProcMap = member.globalStrSigProcMap();
	SigProcArray& globalProcs = globalSigProcMap[signal];
	for (int i = 0; i < globalProcs.size(); i++)
	{
		SigProc& proc = globalProcs[i];
		if (proc == object)
		{
			proc(this, value);
		}
	}
	return true;
}

bool BObject::attach(int signal, proc method)
{
	if (signal == 0)
		return false;
	SigProc sp(this, method);
	SigProcMap& globalSigProcMap = member.globalSigProcMap();
	SigProcArray& procs = globalSigProcMap[signal];
	procs.append(sp);
	return true;
}
bool BObject::attach(BObject* object, int signal, proc method)
{
	if (!object || signal == 0)
		return false;
	SigProc sp(this, method);
	SigProcArray& procs = object_member(object)->sigProcMap[signal];
	if (!procs.contain(sp))
		procs.append(sp);
	return true;
}
bool BObject::attach(const BString& signal, proc method)
{
	if (signal.empty())
		return false;
	SigProc sp(this, method);
	StrSigProcMap& globalStrSigProcMap = member.globalStrSigProcMap();
	SigProcArray& procs = globalStrSigProcMap[signal];
	if (!procs.contain(sp))
		procs.append(sp);
	return true;
}
bool BObject::attach(BObject* object, const BString& signal, proc method)
{
	if (!object || signal.empty())
		return false;
	SigProc sp(this, method);
	SigProcArray& procs = object_member(object)->strSigProcMap[signal];
	if (!procs.contain(sp))
		procs.append(sp);
	return true;
}


